package com.xy.job.executor.core.server

import com.xy.job.core.api.request.JobKillParam
import com.xy.job.core.api.request.JobLogParam
import com.xy.job.core.api.request.JobTriggerParam
import com.xy.job.core.api.response.wrapperResponse
import com.xy.job.executor.config.LocalDateTimeSerializer
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import org.slf4j.LoggerFactory
import java.time.LocalDateTime
import java.util.concurrent.TimeUnit

class EmbedServer(
    private val port: Int,
    private val executorServiceBiz: ExecutorServiceBiz,
) {

    private val server = embeddedServer(
        Netty,
        port = port,
        host = "0.0.0.0",
        module = {
            configureRouting()
        }
    )
    private val log = LoggerFactory.getLogger(this::class.java)

    private val jsonConfig = Json {
        serializersModule = SerializersModule {
            contextual(LocalDateTime::class, LocalDateTimeSerializer)
        }
        ignoreUnknownKeys = true
    }

    private fun Application.configureRouting() {
        install(ContentNegotiation) {
            json(jsonConfig)
        }
        routing {
            post("/private/job/trigger") {
                val param: JobTriggerParam = this.call.receive()
                val responseWrapper = wrapperResponse { executorServiceBiz.trigger(param) }
                call.respond(responseWrapper)
            }
            post("/private/job/kill") {
                val param: JobKillParam = this.call.receive()
                val responseWrapper = wrapperResponse { executorServiceBiz.kill(param) }
                call.respond(responseWrapper)
            }
            post("/private/job/log") {
                val param: JobLogParam = this.call.receive()
                val responseWrapper = wrapperResponse { executorServiceBiz.log(param) }
                call.respond(responseWrapper)
            }
        }
    }

    fun start() {
        start(false)
    }

    fun start(wait: Boolean) {
        log.info("xy-job executor embedServer started on port {}", port)
        server.start(wait)
    }

    fun stop() {
        log.info("xy-job executor embedServer stop")
        server.stop(1, 1, TimeUnit.SECONDS)
    }

    fun addShutdownHook(stop: () -> Unit) {
        server.addShutdownHook(stop)
    }
}